package main

import "fmt"

type Sayer interface {
	Say() string
}

type Cat struct {
}

func (c Cat) Say() string {
	return "喵喵喵"
}

type Dog struct {
}

func (d Dog) Say() string {
	return "汪汪汪"
}
func AA(i Sayer) {
	say := i.Say()
	fmt.Println(say)
}

type Mover interface {
	move()
}
//值接收者实现接口
//func (d Dog) move() {
//	fmt.Println("狗会动")
//}
//指针接收者实现接口
//实现Mover接口的是*dog类型，所以不能给x传入dog类型的wangcai，此时x只能存储*dog类型的值。
func (d *Dog)move () {
	fmt.Println("狗")
}


/**
		   接口是一个或多个方法签名的集合。
    任何类型的方法集中只要拥有该接口'对应的全部方法'签名。
    就表示它 "实现" 了该接口，无须在该类型上显式声明实现了哪个接口。
    这称为Structural Typing。
    所谓对应方法，是指有相同名称、参数列表 (不包括参数名) 以及返回值。
    当然，该类型还可以有其他方法。

    接口只有方法声明，没有实现，没有数据字段。
    接口可以匿名嵌入其他接口，或嵌入到结构中。
    对象赋值给接口时，会发生拷贝，而接口内部存储的是指向这个复制品的指针，既无法修改复制品的状态，也无法获取指针。
    只有当接口存储的类型和对象都为nil时，接口才等于nil。
    接口调用不会做receiver的自动转换。
    接口同样支持匿名字段方法。
    接口也可实现类似OOP中的多态。
    空接口可以作为任何类型数据的容器。
    一个类型可实现多个接口。
    接口命名习惯以 er 结尾。
*/
func main() {
Test02()
}

func  Test02()  {
	var x Mover
	var wangyi=Dog{}//旺财是dog类型
//	x=wangyi
	var fugui=&Dog{} // 富贵是*dog类型
	x=fugui
	x.move()
	//不管是dog结构体还是结构体指针*dog类型的变量都可以赋值给该接口变量
	//因为Go语言中有对指针类型变量求值的语法糖，dog指针fugui内部会自动求值*fugui
}
func Test01()  {
	c := Cat{}
	d := Dog{}
	AA(c)
	AA(d)
	fmt.Println()
	//接口类型变量能够存储所有实现了该接口的实例。 例如上面的示例中，Sayer类型的变量能够存储dog和cat类型的变量。
	var x Sayer
	a := Cat{}
	b := Dog{}
	x = a
	x.Say()
	x = b
	x.Say()
}